package com.inspur.edp.web.form.process.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.GspProject;
import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import com.inspur.edp.metadata.businesstype.api.MdBizTypeMappingService;
import com.inspur.edp.task.entity.ActionParameter;
import com.inspur.edp.task.entity.TaskCenterRegistry;
import com.inspur.edp.task.entity.TaskRpcDefinition;
import com.inspur.edp.web.common.customexception.WebCustomException;
import com.inspur.edp.web.common.metadata.MetadataUtility;
import com.inspur.edp.web.common.serialize.SerializeUtility;
import com.inspur.edp.web.form.process.constant.I18nExceptionConstant;
import com.inspur.edp.web.form.process.entity.ProcessParam;
import com.inspur.edp.web.form.process.utils.BEUtils;
import com.inspur.edp.web.form.process.utils.VOUtils;
import com.inspur.edp.web.formmetadata.formformat.FormFormatHandler;
import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent;
import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM;
import com.inspur.edp.wf.bizprocess.entity.*;
import com.inspur.edp.wf.bizprocess.service.FormFormatRpcService;
import io.iec.edp.caf.businessobject.api.entity.DevBasicBoInfo;
import io.iec.edp.caf.businessobject.api.service.DevBasicInfoService;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.rpc.client.RpcClassHolder;
import io.iec.edp.caf.runtime.function.api.data.FunctionObject;
import io.iec.edp.caf.runtime.function.api.manager.FuncManager;
import com.inspur.edp.task.service.TaskCenterRegistryService;
import org.apache.commons.lang3.StringUtils;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class FormProcessManager {
    private TaskCenterRegistryService registryService;
    private FuncManager funcManager;
    private DevBasicInfoService devBasicInfoService;

    private static class LazyHolder {
        private static final FormProcessManager INSTANCE = new FormProcessManager();
    }

    private FormProcessManager() {
    }

    public static final FormProcessManager getInstance() {
        /* 25 */
        return LazyHolder.INSTANCE;
    }

    private TaskCenterRegistryService getRegistryService() {
        if (this.registryService == null) {
            this.registryService = SpringBeanUtils.getBean(TaskCenterRegistryService.class);
        }
        return this.registryService;
    }
    private FuncManager getFuncManager() {
        if (this.funcManager == null) {
            this.funcManager = SpringBeanUtils.getBean(FuncManager.class);
        }
        return this.funcManager;
    }


    private DevBasicInfoService getDevBasicInfoService(){
        if (this.devBasicInfoService == null) {
            this.devBasicInfoService = SpringBeanUtils.getBean(DevBasicInfoService.class);
        }
        return this.devBasicInfoService;
    }

    /**
     * 发布为表单格式
     * @param formId
     * @param formPath
     */
    public void publishFormFormat(String formId, String formPath) {
        List<GspMetadata>  gspMetadataList =  MetadataUtility.getInstance().getMetadataListWithDesign(formPath);
        String unifiedPath = formPath.replace('\\', '/');
        if (unifiedPath.startsWith("/")) {
            unifiedPath = unifiedPath.substring(1);
        }
        //1.获取表单元数据
        GspMetadata md = gspMetadataList.stream().filter(item -> item.getHeader().getId().equals(formId)).findFirst().orElse(null);
        if (md == null) {
            throw new WebCustomException(I18nExceptionConstant.WEB_FORM_PROCESS_ERROR_0001, new String[]{formId, unifiedPath});
        }
        md = MetadataUtility.getInstance().getMetadataWithDesign(md.getHeader().getFileName(),unifiedPath);

        MetadataHeader header = md.getHeader();
        RpcClassHolder rpcHelper = SpringBeanUtils.getBean(RpcClassHolder.class);
        FormFormatRpcService service = rpcHelper.getRpcClass(FormFormatRpcService.class);
        MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class);
        GspProject project = metadataService.getGspProjectInfo(formPath);
        FormFormatHandler handler = FormFormatHandler.getFormFormatHandler(header.getType());

        FormMetadataContent content = (FormMetadataContent) md.getContent();
        JsonNode formContent = content.getContents();
        JsonNode formRulePushModeNode = formContent.at("/options/formRulePushMode");
        String formRulePushMode = "";
        if (formRulePushModeNode != null) {
            formRulePushMode = formRulePushModeNode.textValue();
        }

        // 判断是否历史数据参数
        if ("MobileForm".equals(header.getType())) {
            if (formRulePushMode == null || StringUtils.isBlank(formRulePushMode) || "pushToWF".equals(formRulePushMode)) {
                //查找出主表卡片页面
                JsonNode page = this.getMobilePages( md);
                FormFormat formFormat = this.generateFormFormat( md,project,page);
                service.addFormFormat(formFormat);
            } else {
                handler.pushFormFormat(md, "pf", formPath);
            }
        } else {

            if (formRulePushMode == null || StringUtils.isBlank(formRulePushMode)  || "pushToWF".equals(formRulePushMode)) {
                FormFormat formFormat = this.generateFormFormat( md,project,null);
                service.addFormFormat(formFormat);
            } else {
                handler.pushFormFormat(md, "pf", formPath);
            }
        }
    }

    /**
     * 构造表单格式信息
     * @param md
     * @param project
     * @return
     */
    private FormFormat generateFormFormat(GspMetadata md,GspProject project,JsonNode page){
        MetadataHeader header = md.getHeader();
        String deploymentPath = project.getSuDeploymentPath();
        String projectName = project.getMetadataProjectName().toLowerCase();
        String url = "/" + deploymentPath + "/web/" + projectName + "/index.html#/" + header.getCode();

        if ("MobileForm".equals(header.getType())) {
            String uri = page.get("route").get("uri").asText();
            url = "/" + deploymentPath + "/mob/" + projectName + "/index.html#/" + header.getCode()+ "/" + uri;
        }

        FormFormat ff = new FormFormat();
        ff.setId(header.getId());
        ff.setCode(header.getCode());
        ff.setName(header.getName());
        ff.setUrlType("url");
        ff.setFormUrl(url);
        UrlParameter actionParam = new UrlParameter();
        actionParam.setCode("action");
        actionParam.setName("动作");
        if ("MobileForm".equals(header.getType())) {
            actionParam.setValue("LoadAndEditForCard");
        }else{
            actionParam.setValue("LoadAndView1");
        }
        UrlParameter idParam = new UrlParameter();
        idParam.setCode("id");
        idParam.setName("内码");
        idParam.setValue("{\"expr\":\"DefaultFunction.GetContextParameter(\\\"dataId\\\")\",\"sexpr\":\"\"}\n");
        List<UrlParameter> list = Arrays.asList(new UrlParameter[]{actionParam, idParam});
        ff.setUrlParameters(list);
        ff.setFormatType("wf");
        String boId = project.getBizobjectID();
        ff.setBizCategory(getBizTypeId(boId));
        ff.setTerminal("PC");

        if ("MobileForm".equals(header.getType())) {
            ff.setTerminal("Mobile");
            MobileWFFormFormatManager mobileWFFormFormatManager = MobileWFFormFormatManager.getInstance();
            FormMetadataContent content = (FormMetadataContent) md.getContent();
            JsonNode formContent = content.getContents();
            // 提取按钮
            List<FormButton> btnList = mobileWFFormFormatManager.getButtons(formContent, ff.getId());
            ff.setFormButtons(btnList);
            // 提取字段
            List<FormFieldData> fields = mobileWFFormFormatManager.getFields(formContent, ff.getId());
            ff.setFormFields(fields);
            // 提取方法,暂时未用到
//            List<FormMethod> methods = mobileWFFormFormatManager.getMethods(formContent, ff.getId());
//            ff.setFormMethods(methods);

        }

        return ff;
    }

    private String getBizTypeId(String bizObjectId) {
        MdBizTypeMappingService service = (MdBizTypeMappingService) SpringBeanUtils.getBean(MdBizTypeMappingService.class);
        List<String> bizTypeIds = service.getBizTypeIdsByBoId(bizObjectId);
        return (bizTypeIds == null || bizTypeIds.size() == 0) ? "" : bizTypeIds.get(0);
    }

    /**
     * 获取移动主表卡片页面
     * @param md
     * @return
     */
    private JsonNode getMobilePages(GspMetadata md){
        JsonNode result = null;

        FormMetadataContent content = (FormMetadataContent) md.getContent();
        JsonNode formContent = content.getContents();

        JsonNode components = formContent.get("module").get("components");
        JsonNode viewmodels = formContent.get("module").get("viewmodels");

        if(components != null && components.size() > 0 && viewmodels != null && viewmodels.size() > 0 ){
            for(JsonNode component:components){
                //页面
                if(component.get("componentType") == null || !component.get("componentType").asText().equals("Page") ){
                    continue;
                }
                //卡片
                if(component.get("pageType") == null ||  !component.get("pageType").asText().equals("Card")){
                    continue;
                }
                //有路由地址
                if(component.get("route") == null || component.get("route").get("uri")  == null){
                    continue;
                }
                //主表
                for(JsonNode viewmodel:viewmodels){
                    if(viewmodel.get("id") == null || !viewmodel.get("id").equals(component.get("viewModel"))){
                        continue;
                    }
                    if(viewmodel.get("bindTo") == null || viewmodel.get("bindTo").asText().equals("") || viewmodel.get("bindTo").asText().equals("/") ){
                        result = component;

                    }
                }
                if(result != null){
                    break;
                }
            }
        }
        return result;
    }


    /**
     * 注册流程到流程中心
     * @param param
     * @return
     */
    @Transactional
    public boolean mobileRegisterToProccessCenter(ProcessParam param) {
        String formPath = param.getFormPath();
        List<GspMetadata>  gspMetadataList =  MetadataUtility.getInstance().getMetadataListWithDesign(formPath);
        String unifiedPath = formPath.replace('\\', '/');
        if (unifiedPath.startsWith("/")) {
            unifiedPath = unifiedPath.substring(1);
        }
        //1.获取设计时表单元数据
        GspMetadata formMetadata = gspMetadataList.stream().filter(item -> item.getHeader().getId().equals(param.getFormId())).findFirst().orElse(null);
        if (formMetadata == null) {
            throw new WebCustomException(I18nExceptionConstant.WEB_FORM_PROCESS_ERROR_0001, new String[]{param.getFormId(), unifiedPath});
        }
        formMetadata = MetadataUtility.getInstance().getMetadataWithDesign(formMetadata.getHeader().getFileName(),unifiedPath);
        FormMetadataContent content = (FormMetadataContent) formMetadata.getContent();
        JsonNode formContent = content.getContents();
        String voId = formContent.at("/module/schemas/0/id").textValue();
        if(StringUtils.isBlank(voId)){
            throw new WebCustomException(I18nExceptionConstant.WEB_FORM_PROCESS_ERROR_0002);
        }

        //2.设计时获取vo，草稿使用
        GspMetadata voMetadata = gspMetadataList.stream().filter(item -> item.getHeader().getId().equals(voId)).findFirst().orElse(null);
        if(voMetadata != null){
            voMetadata = MetadataUtility.getInstance().getMetadataWithDesign(voMetadata.getHeader().getFileName(),unifiedPath);
        }

        //3.设计时获取be,草稿需要
        GspMetadata beMetadata = null;
        String beId = "";
        String backProjectPath = "";
        String bePath  = "";
        if(voMetadata != null ){
            bePath = unifiedPath.replace("-front/metadata/components","-back/metadata/be");
            backProjectPath = unifiedPath.replace("-front/metadata/components","-back/metadata");

            List<GspMetadata>  backMetadataList =  MetadataUtility.getInstance().getMetadataListWithDesign(bePath);
            String curBeId = ((GspViewModel) voMetadata.getContent()).getMapping().getTargetMetadataId();
            beId = curBeId;
            if(StringUtils.isNotBlank(beId) && backMetadataList !=null && backMetadataList.size() > 0){
                beMetadata = backMetadataList.stream().filter(item -> item.getHeader().getId().equals(curBeId)).findFirst().orElse(null);
                if(beMetadata != null){
                    beMetadata = MetadataUtility.getInstance().getMetadataWithDesign(beMetadata.getHeader().getFileName(),bePath);
                }
            }
        }

        //4.注册到流程中心
        this.addTaskRegistry(param,beMetadata);

        //5.处理be和vo添加草稿构件的逻辑。
        if(voMetadata !=null){
            if(beMetadata != null){
                //表单和be、vo在同一个工程下，在vo和be上添加构件
                boolean needAddDraftCmp = BEUtils.addDraftCmpAndSave(beMetadata, true,backProjectPath);
                if (needAddDraftCmp) {
                    VOUtils.addDraftCmp(param, beMetadata,voMetadata);
                }
            }else if(StringUtils.isNotBlank(beId)){
                //如果表单和be不在同一个工程下
                beMetadata = MetadataUtility.getInstance().getMetadataInRuntime(beId);
                boolean needAddDraftCmp = BEUtils.addDraftCmpAndSave(beMetadata, false,backProjectPath);
                if (needAddDraftCmp) {
                    VOUtils.addDraftCmp(param, beMetadata,voMetadata);
                }
            }
        }


        return true;
    }

    /**
     * 注册到流程中心
     * @param param
     */
    private void addTaskRegistry(ProcessParam param,GspMetadata beMetadata) {
        String menuId = param.getFormMenu();
        //1.新建实体，并设置属性值
        TaskCenterRegistry registry = new TaskCenterRegistry();
        registry.setProcessCategory(param.getProcessCategory()); //流程分类id，必须
        registry.setIcon("");//图标，可选
        registry.setDescription(param.getDescription()); //流程描述，可选
        registry.setBizCategory(param.getBizCategory());//业务种类id
        registry.setUrlType("app");
        registry.setFormUrl(menuId);
        registry.setTerminal("mobile");//启用终端，web：PC端；app：移动端
        FunctionObject menu = this.getFuncManager().getFunc(menuId);
        if (menu == null) {
            throw new WebCustomException(I18nExceptionConstant.WEB_FORM_PROCESS_ERROR_0003, new String[]{menuId});
        }
        registry.setBizOperationId(menu.getBizOpId());
        registry.setEnable(param.getEnable());//是否启用，必须

        //2.设置打开制单页面需要的参数（可选）
        ArrayList<ActionParameter> actionParameters = new ArrayList<>();
        ActionParameter actionParameter = new ActionParameter("action", "LoadAndAddForCard");
        actionParameters.add(actionParameter);
        ActionParameter backUrlParameter = new ActionParameter("backUrl", "/platform/runtime/wf/webapp/proc-center-mobile/index.html");
        actionParameters.add(backUrlParameter);
        registry.setFormParams(actionParameters); // 设置打开制单页面需要的参数

        //3.设置打开草稿页面需要的参数（使用我的草稿时预置，可选）
        ArrayList<ActionParameter> draftParams = new ArrayList<>();
        ActionParameter mobileEditParam = new ActionParameter("action", "LoadAndEditForCard");
        draftParams.add(mobileEditParam);
        draftParams.add(backUrlParameter);


        draftParams.add(new ActionParameter("id", "${TaskDraft.dataId}"));
        registry.setDraftParams(draftParams);

        //4.设置删除草稿的rpc接口地址（使用我的草稿时预置，可选）
        if(beMetadata != null){
            DevBasicBoInfo devBasicBoInfo = this.getDevBasicInfoService().getDevBasicBoInfo(beMetadata.getHeader().getBizobjectID());
            String suCode =  devBasicBoInfo.getSuCode();
            TaskRpcDefinition taskRpcDefinition = new TaskRpcDefinition();
            taskRpcDefinition.setSuCode(suCode);//su code
            taskRpcDefinition.setServiceId("com.inspur.common.component.api.service.draft.service.ITaskDraftCallBackService.delete");//删除业务单据的serviceId
            ArrayList<ActionParameter> rpcParams = new ArrayList<>();//删除接口需要的参数
            // 顺序必须是  beId  id。
            rpcParams.add(new ActionParameter("beId", beMetadata.getHeader().getId()));
            rpcParams.add(new ActionParameter("id", "${TaskDraft.dataId}"));//变量取值，表示取草稿的数据id
            taskRpcDefinition.setParameters(rpcParams);
            registry.setBizInstDeleteRpc(taskRpcDefinition);
        }

        //5.调用RPC，执行新增
        TaskCenterRegistry taskEntity = this.getRegistryService().addTaskCenterRegistry(registry);
        if (taskEntity == null) {
            throw new WebCustomException(I18nExceptionConstant.WEB_FORM_PROCESS_ERROR_0004, new String[]{menu.getName()});
        }
    }

}

